﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using snat.model;
using snat.algorithms;
using algorithms.utils.resultsets;

namespace algorithms.utils.metrics
{
    public class FloydWarshall : IAlgorithm
    {
        /// <summary>
        /// The Floyd Warshall algorithm for all pairs shortest path distance.
        /// </summary>
        private float[,] Da, Db, currentD, lastD, swapD;
        private Dictionary<BaseNode, int> indexLookup = new Dictionary<BaseNode, int>();
        private Dictionary<int, BaseNode> basenodeLookup;
        int nodeCount=0;


        public ResultMatrix<BaseNode> LastResult {
            get; private set;
        }

        public FloydWarshall() {
            foreach (BaseNode b in NetworkModel.Instance.Nodes.Values) {
                indexLookup.Add(b, nodeCount++);
            }
            basenodeLookup = indexLookup.ToDictionary(e => e.Value, e => e.Key);
        }


        public ResultMatrix<BaseNode> RunFW() {


            Da = new float[nodeCount, nodeCount];
            Db = new float[nodeCount, nodeCount];
            currentD = Da;
            lastD = Db;

            Console.WriteLine("created");
            //step 1 : initalize the first state
            for (int i = 0; i < nodeCount; i++) {
                for (int j = 0; j < nodeCount; j++) {
                    if (i == j) {
                        currentD[i, j] = 0F;
                    }
                    else if (basenodeLookup[i].OverlayOutEdges.Exists(e => e.Target.ID == basenodeLookup[j].ID)) { //todo use strength
                        currentD[i, j] = 1F;
                    }
                    else {
                        currentD[i, j] = float.PositiveInfinity;
                    }
                }
            }

            Console.WriteLine("inited");
            //The actual algo


            for (int k = 0; k < nodeCount; k++) {
                Console.WriteLine("\t{0}/{1}", k, nodeCount - 1);
                //let whatever be whatever
                swapD = lastD;
                lastD = currentD;
                currentD = swapD;
                for (int i = 0; i < nodeCount; i++) {
                    for (int j = 0; j < nodeCount; j++) {
                        currentD[i, j] = Math.Min(lastD[i, j], lastD[i, k] + lastD[k, j]);
                    }
                }
            }
            LastResult = new ResultMatrix<BaseNode>(currentD, indexLookup);
            return LastResult;
        }





        #region IAlgorithm Members

        public string Name {
            get { return "Floyd Warshall all pairs shortest paths"; }
        }

        public void Register() {
            //do nothing
        }

        public void DeRegister() {
            //do nothing
        }

        #endregion

    }
}
